package server.user;

import java.sql.ResultSet;
import java.sql.SQLException;

import server.conn.ConnectionThread;
import server.conn.user.UserConnectionThread;
import server.db.DBObject;
import server.db.DataBase;
import server.order.Order;

public class Account extends DBObject {
	public static final String TABLE = "account_log";
	public static final String USER_ID = "userid";
	public static final String SYMBOL = "symbol";
	public static final String AMOUNT = "amount";
	public static final String TIME = "time";
	
	public static final int HISTORY_LIMIT = 50;
	
	private String symbol;
	private User user;
	private float amount;
	private long time;
	
	/**
	 * Create a new account
	 * @param symbol	Currency symbol
	 * @param user		Account owner
	 * @throws SQLException
	 */
	public Account(String symbol, User user) throws SQLException {
		super();
		this.symbol = symbol;
		this.user = user;
		init();
	}
	
	/**
	 * Try to get account information from the database.  If it can't it will create an empty account for the user.
	 * @throws SQLException
	 */
	private final void init() throws SQLException {
		time = System.currentTimeMillis() / 1000;
		try {
			updateAmount();
		} catch (SQLException e) {
			String query = "INSERT INTO "+Account.TABLE+" ("+Account.USER_ID+","+Account.SYMBOL+","+Account.AMOUNT+","+Account.TIME+") ";
			query += "VALUES ("+user.getID()+",\""+symbol+"\",0,"+time+")";
			doUpdate(query);
		}
	}
	
	/**
	 * Query the database to get the latest account balance.
	 * @throws SQLException
	 */
	private void updateAmount() throws SQLException {
		String query = "SELECT "+Account.AMOUNT+","+Account.TIME+" FROM "+Account.TABLE+" WHERE ("+Account.USER_ID+"="+user.getID()+" ";
		query += "AND "+Account.SYMBOL+"=\""+symbol+"\") ORDER BY "+Account.TIME+" DESC LIMIT 1";
		
		ResultSet rs = doQuery(query);
		rs.first();
		
		amount = rs.getFloat(Account.AMOUNT);
		time = rs.getInt(Account.TIME);
	}
	
	/**
	 * Submit current account balance with a time stamp into the database
	 * @throws SQLException
	 */
	private void submitAmount() throws SQLException {
		String query = "INSERT INTO "+Account.TABLE+" ("+Account.USER_ID+", "+Account.SYMBOL+", "+Account.AMOUNT+", "+Account.TIME+") ";
		query += "VALUES ("+user.getID()+",\""+symbol+"\",'"+amount+"',"+time+")";
		
		doUpdate(query);
	}
	
	/**
	 * Get the accounts history
	 * @param limit	Maximum number of records to return
	 * @return	ResultSet containing account information
	 * @throws SQLException
	 */
	public ResultSet getHistory(int limit) throws SQLException {
		if (limit < 1)
			limit = 1;
		
		if (limit > HISTORY_LIMIT)
			limit = HISTORY_LIMIT;
		
		String query = "SELECT "+Account.AMOUNT+","+Account.TIME+" FROM "+Account.TABLE+" WHERE ("+Account.USER_ID+"="+user.getID()+" ";
		query += "AND "+Account.SYMBOL+"=\""+symbol+"\") ORDER BY "+Account.TIME+" DESC LIMIT "+limit;
		
		return doQuery(query);
	}
	
	public String[] getHistoryString(int limit) throws SQLException {
		ResultSet rs = getHistory(limit);

		String[] retArray = new String[DataBase.getRows(rs)];
		
		int counter = 0;
		do {
			retArray[counter++] = symbol+ConnectionThread.SPLIT+rs.getFloat(AMOUNT)+ConnectionThread.SPLIT+rs.getLong(TIME);
		} while (rs.next());
		
		return retArray;

	}
	
	/**
	 * Check to see if account owner can afford an order
	 * @param order	Order to check
	 * @return	True if account owner can afford the order
	 */
	protected boolean checkOrder(Order order) {
		if (order.getRate()*order.getAmount() < amount)
			return true;
		else
			return false;
	}
	
	/**
	 * Make a change to account balance and commit it to the database
	 * @param change	Value of change
	 * @throws SQLException
	 */
	public void makeChange(float change) throws SQLException {
		amount = amount + change;
		time = System.currentTimeMillis()/1000;
		submitAmount();
	}
	
	/**
	 * Set the account balance to a specific amount
	 * @param newAmount	Amount the account balance is to be set to
	 * @throws SQLException
	 */
	public void setAmount(float newAmount) throws SQLException {
		amount = newAmount;
		time = System.currentTimeMillis()/1000;
		submitAmount();
	}
	
	/**
	 * Return a string representation of the account
	 * symbol||amount||time
	 */
	public String toString() {
		try {
			updateAmount();
		} catch (SQLException e) { }
		return symbol+ConnectionThread.SPLIT+amount+ConnectionThread.SPLIT+time;
	}
	
	public String getSymbol() { return symbol; }
	public float getAmount() { return amount; }
	public long getTime() { return time; }
}
